package jps;

import java.util.ArrayList;
import java.util.List;

public class Grid {
    /**
     * The number of rows of the grid.
     */
    private int height;

    /**
     * The number of columns of the grid.
     */
    private int width;

    /**
     * A 2D array of nodes.
     */
    private Node[][] nodes;

    public Grid(int[][] matrix) {
        this.width = matrix[0].length;
        this.height = matrix.length;
        this.nodes = this.buildNodes(width, height, matrix);

    }

    private Node[][] buildNodes(int width, int height, int[][] matrix) {
        Node[][] currNodes = new Node[width][height];
        for (int i = 0; i < height; ++i) {
            for (int j = 0; j < width; ++j) {
                currNodes[i][j] = new Node(j, i);
                if (matrix[i][j] == 1) {
                    currNodes[i][j].setWalkable(false);
                }
            }
        }
        return currNodes;
    }

    public Node getNodeAt(int x, int y) {
        return this.nodes[y][x];
    }

    public boolean isWalkableAt(int x, int y) {
        return this.isInside(x, y) && this.nodes[y][x].isWalkable();
    }

    private boolean isInside(int x, int y) {
        return (x >= 0 && x < this.width) && (y >= 0 && y < this.height);
    }

    public void setWalkableAt(int x, int y, boolean walkable) {
        this.nodes[y][x].setWalkable(walkable);
    }

    public List<Node> getNeighbors(Node node) {
        int x = node.getX();
        int y = node.getY();
        boolean s0 = false;
        boolean s1 = false;
        boolean s2 = false;
        boolean s3 = false;
        List<Node> neighbors = new ArrayList<Node>();
        // ↑
        if (this.isWalkableAt(x, y - 1)) {
            neighbors.add(this.nodes[y - 1][x]);
            s0 = true;
        }
        // →
        if (this.isWalkableAt(x + 1, y)) {
            neighbors.add(this.nodes[y][x + 1]);
            s1 = true;
        }
        // ↓
        if (this.isWalkableAt(x, y + 1)) {
            neighbors.add(this.nodes[y + 1][x]);
            s2 = true;
        }
        // ←
        if (this.isWalkableAt(x - 1, y)) {
            neighbors.add(this.nodes[y][x - 1]);
            s3 = true;
        }
        boolean d0 = s3 && s0;
        boolean d1 = s0 && s1;
        boolean d2 = s1 && s2;
        boolean d3 = s2 && s3;
        // ↖
        if (d0 && this.isWalkableAt(x - 1, y - 1)) {
            neighbors.add(this.nodes[y - 1][x - 1]);
        }
        // ↗
        if (d1 && this.isWalkableAt(x + 1, y - 1)) {
            neighbors.add(this.nodes[y - 1][x + 1]);
        }
        // ↘
        if (d2 && this.isWalkableAt(x + 1, y + 1)) {
            neighbors.add(this.nodes[y + 1][x + 1]);
        }
        // ↙
        if (d3 && this.isWalkableAt(x - 1, y + 1)) {
            neighbors.add(this.nodes[y + 1][x - 1]);
        }
        return neighbors;
    }

}
